home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / b / b.lha / B / src / bed / supr.c < prev    next >
C/C++ Source or Header  |  1988-11-24  |  18KB  |  1,118 lines

  1. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
  2. static char rcsid[] = "$Header: supr.c,v 2.3 84/07/23 13:03:15 guido Exp $";
  3.  
  4. /*
  5.  * B editor -- Superroutines.
  6.  */
  7.  
  8. #include "b.h"
  9. #include "feat.h"
  10. #include "bobj.h"
  11. #include "node.h"
  12. #include "supr.h"
  13. #include "gram.h"
  14.  
  15. /*
  16.  * Compute the length of the ep->s1'th item of node tree(ep->focus).
  17.  */
  18.  
  19. Visible int
  20. lenitem(ep)
  21.     register environ *ep;
  22. {
  23.     register node n = tree(ep->focus);
  24.     register node nn;
  25.  
  26.     if (ep->s1&1) /* Fixed text */
  27.         return fwidth(noderepr(n)[ep->s1/2]);
  28.     /* Else, variable text or a whole node */
  29.     nn = child(n, ep->s1/2);
  30.     return width(nn);
  31. }
  32.  
  33.  
  34. /*
  35.  * Find the largest possible representation of the focus.
  36.  * E.g., a WHOLE can also be represented as a SUBSET of its parent,
  37.  * provided it has a parent.
  38.  * Also, a SUBSET may be extended with some empty left and right
  39.  * items and then look like a WHOLE, etc.
  40.  * This process is repeated until no more improvements can be made.
  41.  */
  42.  
  43. Visible Procedure
  44. grow(ep)
  45.     environ *ep;
  46. {
  47.     subgrow(ep, Yes);
  48. }
  49.  
  50. Visible Procedure
  51. subgrow(ep, ignorespaces)
  52.     register environ *ep;
  53.     bool ignorespaces;
  54. {
  55.     register node n;
  56.     register int sym;
  57.     register int i;
  58.     register int len;
  59.     register string repr;
  60.  
  61.     switch (ep->mode) {
  62.     case ATBEGIN:
  63.     case ATEND:
  64.     case VHOLE:
  65.     case FHOLE:
  66.         ritevhole(ep);
  67.         if (ep->mode != FHOLE && ep->mode != VHOLE || lenitem(ep) == 0)
  68.             leftvhole(ep);
  69.  
  70.     }
  71.  
  72.     for (;;) {
  73.         n = tree(ep->focus);
  74.         sym = symbol(n);
  75.  
  76.         switch (ep->mode) {
  77.  
  78.         case VHOLE:
  79.         case FHOLE:
  80.             if ((sym == Optional || sym == Hole) && ep->s2 == 0) {
  81.                 ep->mode = WHOLE;
  82.                 continue;
  83.             }
  84.             if (lenitem(ep) <= 0) {
  85.                 ep->mode = SUBSET;
  86.                 ep->s2 = ep->s1;
  87.                 continue;
  88.             }
  89.             return;
  90.  
  91.         case ATBEGIN:
  92.         case ATEND:
  93.             if (sym == Optional || sym == Hole) {
  94.                 ep->mode = WHOLE;
  95.                 continue;
  96.             }
  97.             return;
  98.  
  99.         case SUBRANGE:
  100.             if (ep->s1&1) {
  101.                 repr = noderepr(n)[ep->s1/2];
  102.                 len = fwidth(repr);
  103.                 if (!ignorespaces) {
  104.                   while (ep->s2 > 0 && repr[ep->s2-1] == ' ')
  105.                     --ep->s2;
  106.                   while (ep->s3 < len && repr[ep->s3+1] == ' ')
  107.                     ++ep->s3;
  108.                 }
  109.             }
  110.             else
  111.                 len = Length((value) firstchild(n));
  112.             if (ep->s2 == 0 && ep->s3 >= len - 1) {
  113.                 ep->mode = SUBSET;
  114.                 ep->s2 = ep->s1;
  115.                 continue;
  116.             }
  117.             return;
  118.  
  119.         case SUBSET:
  120.             subgrsubset(ep, ignorespaces);
  121.             if (ep->s1 == 1) {
  122.                 if (ep->s2 == 2*nchildren(n) + 1) {
  123.                     ep->mode = WHOLE;
  124.                     continue;
  125.                 }
  126.                 if (ep->s2 == 2*nchildren(n) - 1 && issublist(sym)) {
  127.                     ep->mode = SUBLIST;
  128.                     ep->s3 = 1;
  129.                     return;
  130.                 }
  131.             }
  132.             return;
  133.  
  134.         case SUBLIST:
  135.             for (i = ep->s3; i > 0; --i)
  136.                 n = lastchild(n);
  137.             sym = symbol(n);
  138.             if (sym == Optional) {
  139.                 ep->mode = WHOLE;
  140.                 continue;
  141.             }
  142.             return;
  143.  
  144.         case WHOLE:
  145.             ep->s1 = 2*ichild(ep->focus);
  146.             if (up(&ep->focus)) {
  147.                 ep->mode = SUBSET;
  148.                 ep->s2 = ep->s1;
  149.                 higher(ep);
  150.                 continue;
  151.             }
  152.             return; /* Leave as WHOLE if there is no parent */
  153.  
  154.         default:
  155.             Abort();
  156.             /* NOTREACHED */
  157.  
  158.         }
  159.         
  160.     }
  161.     /* Not reached */
  162. }
  163.  
  164.  
  165. /*
  166.  * Ditto to find smallest possible representation.
  167.  */
  168.  
  169. Visible Procedure
  170. shrink(ep)
  171.     register environ *ep;
  172. {
  173.     register node n;
  174.     register int sym;
  175.  
  176.     for (;;) {
  177.         n = tree(ep->focus);
  178.         sym = symbol(n);
  179.  
  180.         switch (ep->mode) {
  181.  
  182.         case WHOLE:
  183.             if (sym == Hole || sym == Optional)
  184.                 return;
  185.             ep->mode = SUBSET;
  186.             ep->s1 = 1;
  187.             ep->s2 = 2*nchildren(n) + 1;
  188.             continue;
  189.  
  190.         case SUBLIST:
  191.             if (sym == Hole || sym == Optional) {
  192.                 ep->mode = WHOLE;
  193.                 return;
  194.             }
  195.             if (ep->s3 == 1) {
  196.                 ep->mode = SUBSET;
  197.                 ep->s1 = 1;
  198.                 ep->s2 = 2*nchildren(n) - 1;
  199.                 continue;
  200.             }
  201.             return;
  202.  
  203.         case SUBSET:
  204.             if (sym == Hole || sym == Optional) {
  205.                 ep->mode = WHOLE;
  206.                 return;
  207.             }
  208.             shrsubset(ep);
  209.             if (ep->s1 == ep->s2) {
  210.                 if (isunititem(ep)) {
  211.                     ep->mode = SUBRANGE;
  212.                     ep->s2 = 0;
  213.                     ep->s3 = lenitem(ep) - 1;
  214.                     return;
  215.                 }
  216.                 else {
  217.                     s_downi(ep, ep->s1/2);
  218.                     ep->mode = WHOLE;
  219.                     continue;
  220.                 }
  221.             }
  222.             return;
  223.  
  224.         case SUBRANGE:
  225.             if (sym == Optional || sym == Hole)
  226.                 ep->mode = WHOLE;
  227.             return;
  228.  
  229.         case ATBEGIN:
  230.             ritevhole(ep);
  231.             if (ep->mode == ATBEGIN) {
  232.                 if (sym == Optional || sym == Hole)
  233.                     ep->mode = WHOLE;
  234.                 return;
  235.             }
  236.             continue;
  237.  
  238.         case FHOLE:
  239.         case VHOLE:
  240.             ritevhole(ep);
  241.             if (ep->mode != VHOLE && ep->mode != FHOLE)
  242.                 continue;
  243.             sym = symbol(tree(ep->focus));
  244.             if (sym == Optional || sym == Hole && ep->s2 == 0)
  245.                 ep->mode = WHOLE;
  246.             return;
  247.  
  248.         case ATEND:
  249.             return;
  250.  
  251.         default:
  252.             Abort();
  253.             /* NOTREACHED */
  254.  
  255.         }
  256.     }
  257.     /* Not reached */
  258.  
  259. }
  260.  
  261.  
  262. /*
  263.  * Subroutine to find the largest way to describe a SUBSET focus
  264.  * (modulo surrounding blanks and newlines).
  265.  */
  266.  
  267. Visible Procedure
  268. growsubset(ep)
  269.     environ *ep;
  270. {
  271.     subgrsubset(ep, Yes);
  272. }
  273.  
  274. Visible Procedure
  275. subgrsubset(ep, ignorespaces)
  276.     register environ *ep;
  277.     bool ignorespaces;
  278. {
  279.     register node n = tree(ep->focus);
  280.     register string *rp = noderepr(n);
  281.     register nch21 = nchildren(n)*2 + 1;
  282.     register int i;
  283.  
  284.     Assert(ep->mode == SUBSET);
  285.     for (i = ep->s1; i > 1 && subisnull(n, rp, i-1, ignorespaces); --i)
  286.         ;
  287.     ep->s1 = i;
  288.     for (i = ep->s2; i < nch21 && subisnull(n, rp, i+1, ignorespaces); ++i)
  289.         ;
  290.     ep->s2 = i;
  291. }
  292.  
  293.  
  294. /*
  295.  * Ditto for the smallest way.
  296.  */
  297.  
  298. Visible Procedure /* Ought to be Hidden */
  299. shrsubset(ep)
  300.     register environ *ep;
  301. {
  302.     register node n = tree(ep->focus);
  303.     register string *rp = noderepr(n);
  304.     register int s1 = ep->s1;
  305.     register int s2 = ep->s2;
  306.  
  307.     for (; s1 < s2 && isnull(n, rp, s1); ++s1)
  308.         ;
  309.     ep->s1 = s1;
  310.     for (; s2 > s1 && isnull(n, rp, s2); --s2)
  311.         ;
  312.     ep->s2 = s2;
  313. }
  314.  
  315.  
  316. /*
  317.  * Subroutine for grow/shrink to see whether item i is (almost) invisible.
  318.  */
  319.  
  320. Visible bool
  321. isnull(n, rp, i)
  322.     node n;
  323.     string *rp;
  324.     int i;
  325. {
  326.     return subisnull(n, rp, i, Yes);
  327. }
  328.  
  329. Hidden Procedure
  330. subisnull(n, rp, i, ignorespaces)
  331.     register node n;
  332.     register string *rp;
  333.     register int i;
  334.     bool ignorespaces;
  335. {
  336.     register string repr;
  337.     register node nn;
  338.  
  339.     if (i&1) { /* Fixed text */
  340.         repr = rp[i/2];
  341.         return !Fw_positive(repr) || ignorespaces && allspaces(repr);
  342.     }
  343.     nn = child(n, i/2);
  344.     return width(nn) == 0;
  345. }
  346.  
  347.  
  348. /*
  349.  * Find the rightmost VHOLE which would look the same as the current one.
  350.  */
  351.  
  352. Visible Procedure
  353. ritevhole(ep)
  354.     register environ *ep;
  355. {
  356.     register node n;
  357.     register int ich;
  358.     register int len;
  359.     register int s1save;
  360.  
  361.     for (;;) {
  362.         n = tree(ep->focus);
  363.  
  364.         switch (ep->mode) {
  365.  
  366.         case WHOLE:
  367.             ep->mode = ATEND;
  368.             break;
  369.  
  370.         case VHOLE:
  371.         case FHOLE:
  372.             len = lenitem(ep);
  373.             Assert(len >= 0);
  374.             if (ep->s2 < len)
  375.                 return; /* Hole in middle of string */
  376.             s1save = ep->s1;
  377.             if (nextitem(ep)) {
  378.                 if (isunititem(ep)) {
  379.                     ep->mode = (ep->s1&1) ? FHOLE : VHOLE;
  380.                     ep->s2 = 0;
  381.                 }
  382.                 else if (fwidth(noderepr(child(n, ep->s1/2))[0]) < 0) {
  383.                     /* Next item begins with newline -- avoid */
  384.                     ep->s1 = s1save;
  385.                     return;
  386.                 }
  387.                 else {
  388.                     s_downi(ep, ep->s1/2);
  389.                     ep->mode = ATBEGIN;
  390.                 }
  391.                 break;
  392.             }
  393.             ep->mode = ATEND;
  394.             /* Fall through */
  395.         case ATEND:
  396.             if (!parent(ep->focus) || width(n) < 0)
  397.                 return;
  398.             ich = ichild(ep->focus);
  399.             ep->s1 = 2*ich;
  400.             s_up(ep);
  401.             if (nextitem(ep)) {
  402.                 /* Note -- negative width cannot occur (see test above) */
  403.                 if (isunititem(ep)) {
  404.                     ep->mode = (ep->s1&1) ? FHOLE : VHOLE;
  405.                     ep->s2 = 0;
  406.                 }
  407.                 else {
  408.                     ep->mode = ATBEGIN;
  409.                     s_downi(ep, ep->s1/2);
  410.                 }
  411.                 break;
  412.             }
  413.             continue;
  414.  
  415.         case ATBEGIN:
  416.             if (fwidth(noderepr(n)[0]) < 0)
  417.                 return; /* Already at dangerous position */
  418.             ep->mode = FHOLE;
  419.             ep->s1 = 1;
  420.             ep->s2 = 0;
  421.             continue;
  422.  
  423.         default:
  424.             Abort();
  425.             /* NOTREACHED */
  426.  
  427.         }
  428.     }
  429. }
  430.  
  431.  
  432. /*
  433.  * Ditto to the left.
  434.  */
  435.  
  436. Visible Procedure
  437. leftvhole(ep)
  438.     register environ *ep;
  439. {
  440.     register int ich;
  441.  
  442.     for (;;) {
  443.         switch (ep->mode) {
  444.  
  445.         case WHOLE:
  446.             ep->mode = ATBEGIN;
  447.             break;
  448.  
  449.         case VHOLE:
  450.         case FHOLE:
  451.             if (ep->s2 > 0)
  452.                 return;
  453.             if (previtem(ep)) {
  454.                 if (isunititem(ep)) {
  455.                     ep->mode = (ep->s1&1) ? FHOLE : VHOLE;
  456.                     ep->s2 = lenitem(ep);
  457.                 }
  458.                 else {
  459.                     s_downi(ep, ep->s1/2);
  460.                     ep->mode = ATEND;
  461.                 }
  462.             }
  463.             else if (fwidth(noderepr(tree(ep->focus))[0]) < 0)
  464.                 return;
  465.             else
  466.                 ep->mode = ATBEGIN;
  467.             continue;
  468.  
  469.         case ATBEGIN:
  470.             ich = ichild(ep->focus);
  471.             if (!up(&ep->focus))
  472.                 return;
  473.             higher(ep);
  474.             ep->s1 = 2*ich;
  475.             if (prevnnitem(ep)) {
  476.                 if (isunititem(ep)) {
  477.                     ep->mode = (ep->s1&1) ? FHOLE : VHOLE;
  478.                     ep->s2 = lenitem(ep);
  479.                 }
  480.                 else {
  481.                     s_downi(ep, ep->s1/2);
  482.                     ep->mode = ATEND;
  483.                 }
  484.             }
  485.             else if (fwidth(noderepr(tree(ep->focus))[0]) < 0) {
  486.                 s_downi(ep, ich); /* Undo up */
  487.                 return;
  488.             }
  489.             else
  490.                 ep->mode = ATBEGIN;
  491.             continue;
  492.  
  493.         case ATEND:
  494.             lastnnitem(ep);
  495.             if (isunititem(ep)) {
  496.                 ep->s2 = lenitem(ep);
  497.                 ep->mode = (ep->s1&1) ? FHOLE : VHOLE;
  498.             }
  499.             else
  500.                 s_downi(ep, ep->s1/2);
  501.             continue;
  502.  
  503.         default:
  504.             Abort();
  505.  
  506.         }
  507.     }
  508. }
  509.  
  510.  
  511. /*
  512.  * Safe up, downi, left and rite routines:
  513.  * 1) Rather die than fail;
  514.  * 2) Update ep->highest properly.
  515.  */
  516.  
  517. Visible Procedure
  518. s_up(ep)
  519.     register environ *ep;
  520. {
  521.     if (!up(&ep->focus))
  522.         syserr("s_up failed");
  523.     higher(ep);
  524. }
  525.  
  526. Visible Procedure
  527. s_downi(ep, i)
  528.     register environ *ep;
  529.     register int i;
  530. {
  531.     if (!downi(&ep->focus, i))
  532.         syserr("s_downi failed");
  533. }
  534.  
  535. Visible Procedure
  536. s_down(ep)
  537.     register environ *ep;
  538. {
  539.     if (!down(&ep->focus))
  540.         syserr("s_down failed");
  541. }
  542.  
  543. Visible Procedure
  544. s_downrite(ep)
  545.     register environ *ep;
  546. {
  547.     if (!downrite(&ep->focus))
  548.         syserr("s_downrite failed");
  549. }
  550.  
  551. Visible Procedure
  552. s_left(ep)
  553.     register environ *ep;
  554. {
  555.     register int ich = ichild(ep->focus);
  556.  
  557.     s_up(ep);
  558.     s_downi(ep, ich-1);
  559. }
  560.  
  561. Visible Procedure
  562. s_rite(ep)
  563.     register environ *ep;
  564. {
  565.     register int ich = ichild(ep->focus);
  566.  
  567.     s_up(ep);
  568.     s_downi(ep, ich+1);
  569. }
  570.  
  571.  
  572. /*
  573.  * Find next item in a subset, using ep->s1 as index.
  574.  * (This used to be less trivial, so it's still a subroutine rather than
  575.  * coded in-line or as a macro.)
  576.  */
  577.  
  578. Visible bool
  579. nextitem(ep)
  580.     register environ *ep;
  581. {
  582.     if (ep->s1 >= 2*nchildren(tree(ep->focus)) + 1)
  583.         return No; /* Already at last item */
  584.     ++ep->s1;
  585.     return Yes;
  586. }
  587.  
  588.  
  589. /*
  590.  * Ditto for previous.
  591.  */
  592.  
  593. Visible bool
  594. previtem(ep)
  595.     register environ *ep;
  596. {
  597.     if (ep->s1 <= 1
  598.         || ep->s1 == 2 && fwidth(noderepr(tree(ep->focus))[0]) < 0)
  599.         return No; /* Already at first item */
  600.     --ep->s1;
  601.     return Yes;
  602. }
  603.  
  604.  
  605. /*
  606.  * Test whether item ep->s1 is "small", i.e., fixed or varying text
  607.  * but not a whole subtree.
  608.  */
  609.  
  610. Visible bool
  611. isunititem(ep)
  612.     register environ *ep;
  613. {
  614.     return (ep->s1&1) || Type(child(tree(ep->focus), ep->s1/2)) == Tex;
  615. }
  616.  
  617.  
  618. /*
  619.  * Check for consistent mode information.
  620.  */
  621.  
  622. Visible bool
  623. checkep(ep)
  624.     register environ *ep;
  625. {
  626.     switch (ep->mode) {
  627.  
  628.     case FHOLE:
  629.         if (!(ep->s1&1))
  630.             break;
  631.         if (ep->s2 < 0 || ep->s2 > lenitem(ep))
  632.             break;
  633.         return Yes;
  634.  
  635.     case VHOLE:
  636.         if (!(ep->s1&1)) {
  637.             if (Type(child(tree(ep->focus), ep->s1/2)) != Tex)
  638.                 break;
  639.         }
  640.         if (ep->s2 < 0 || ep->s2 > lenitem(ep))
  641.             break;
  642.         return Yes;
  643.  
  644.     case SUBSET:
  645.         if (ep->s2 == ep->s1 && isunititem(ep) && lenitem(ep) <= 0)
  646.             break;
  647.         return Yes;
  648.  
  649.     default:
  650.         return Yes;
  651.  
  652.     }
  653.     dbmess(ep);
  654.     return No;
  655. }
  656.  
  657.  
  658. /*
  659.  * Like {next,prev,first,last}item, but with empty items skipped
  660.  * (i.e., those with length <= 0).
  661.  */
  662.  
  663. Visible bool
  664. nextnnitem(ep)
  665.     register environ *ep;
  666. {
  667.     register int s1save = ep->s1;
  668.  
  669.     while (nextitem(ep)) {
  670.         if (lenitem(ep) != 0)
  671.             return Yes;
  672.     }
  673.     ep->s1 = s1save;
  674.     return No;
  675. }
  676.  
  677. Visible bool
  678. prevnnitem(ep)
  679.     register environ *ep;
  680. {
  681.     register int s1save = ep->s1;
  682.     register int len;
  683.  
  684.     while (previtem(ep)) {
  685.         len = lenitem(ep);
  686.         if (len > 0 || len < 0 && ep->s1 > 1)
  687.             return Yes;
  688.     }
  689.     ep->s1 = s1save;
  690.     return No;
  691. }
  692.  
  693.  
  694. Visible Procedure
  695. firstnnitem(ep)
  696.     register environ *ep;
  697. {
  698.     ep->s1 = fwidth(noderepr(tree(ep->focus))[0]) < 0 ? 2 : 1;
  699.     while (lenitem(ep) == 0) {
  700.         if (!nextitem(ep))
  701.             break;
  702.     }
  703.     return;
  704. }
  705.  
  706. Visible Procedure
  707. lastnnitem(ep)
  708.     register environ *ep;
  709. {
  710.     ep->s1 = 2*nchildren(tree(ep->focus)) + 1;
  711.     while (lenitem(ep) == 0) {
  712.         if (!previtem(ep))
  713.             break;
  714.     }
  715.     return;
  716. }
  717.  
  718.  
  719. /*
  720.  * Prepare the focus for insertion.
  721.  * If the focus isn't a hole, make a hole just before it which becomes the
  722.  * new focus.
  723.  * Also repair strange statuses left by moves, so we may have more chance
  724.  * to insert a character.
  725.  */
  726.  
  727. Visible Procedure
  728. fixit(ep)
  729.     register environ *ep;
  730. {
  731.     /* First, make a hole if it's not already a hole. */
  732.  
  733.     switch (ep->mode) {
  734.  
  735.     case FHOLE:
  736.         break;
  737.  
  738.     case VHOLE:
  739.         if (ep->s1&1)
  740.             ep->mode = FHOLE;
  741.         break;
  742.  
  743.     case SUBRANGE:
  744.         if (ep->s1&1)
  745.             ep->mode = FHOLE;
  746.         else
  747.             ep->mode = VHOLE;
  748.         break;
  749.  
  750.     case SUBSET:
  751.         if (ep->s1&1) {
  752.             if (ep->s1 == 1)
  753.                 ep->mode = ATBEGIN;
  754.             else {
  755.                 ep->mode = FHOLE;
  756.                 ep->s2 = 0;
  757.             }
  758.         }
  759.         else if (Type(child(tree(ep->focus), ep->s1/2)) == Tex) {
  760.             ep->mode = VHOLE;
  761.             ep->s2 = 0;
  762.         }
  763.         else {
  764.             s_downi(ep, ep->s1/2);
  765.             ep->mode = ATBEGIN;
  766.         }
  767.         break;
  768.  
  769.     case ATBEGIN:
  770.     case SUBLIST:
  771.     case WHOLE:
  772.         ep->mode = ATBEGIN;
  773.         break;
  774.  
  775.     case ATEND:
  776.         break;
  777.  
  778.     default:
  779.         Abort();
  780.     }
  781.  
  782.     leftvhole(ep);
  783.     if (ep->mode == ATEND && symbol(tree(ep->focus)) == Hole)
  784.         ep->mode = WHOLE; /***** Experiment! *****/
  785. }
  786.  
  787.  
  788. /*
  789.  * Small utility to see if a string contains only spaces
  790.  * (this is true for the empty string "").
  791.  * The string pointer must not be null!
  792.  */
  793.  
  794. Visible bool
  795. allspaces(str)
  796.     register string str;
  797. {
  798.     Assert(str);
  799.     for (; *str; ++str) {
  800.         if (*str != ' ')
  801.             return No;
  802.     }
  803.     return Yes;
  804. }
  805.  
  806.  
  807. /*
  808.  * Function to compute the actual width of the focus.
  809.  */
  810.  
  811. Visible int
  812. focwidth(ep)
  813.     register environ *ep;
  814. {
  815.     node nn;
  816.     register node n = tree(ep->focus);
  817.     register string *rp = noderepr(n);
  818.     register int i;
  819.     register int w;
  820.     int len = 0;
  821.  
  822.     switch (ep->mode) {
  823.  
  824.     case VHOLE:
  825.     case FHOLE:
  826.     case ATEND:
  827.     case ATBEGIN:
  828.         return 0;
  829.  
  830.     case WHOLE:
  831.         return width(n);
  832.  
  833.     case SUBRANGE:
  834.         return ep->s3 - ep->s2 + 1;
  835.  
  836.     case SUBSET:
  837.         for (i = ep->s1; i <= ep->s2; ++i) {
  838.             if (i&1)
  839.                 w = fwidth(rp[i/2]);
  840.             else {
  841.                 nn = child(n, i/2);
  842.                 w = width(nn);
  843.             }
  844.             if (w < 0 && len >= 0)
  845.                 len = w;
  846.             else if (w >= 0 && len < 0)
  847.                 ;
  848.             else
  849.                 len += w;
  850.         }
  851.         return len;
  852.  
  853.     case SUBLIST:
  854.         len = width(n);
  855.         for (i = ep->s3; i > 0; --i)
  856.             n = lastchild(n);
  857.         w = width(n);
  858.         if (w < 0 && len >= 0)
  859.             return w;
  860.         if (w >= 0 && len < 0)
  861.             return len;
  862.         return len - w;
  863.  
  864.     default:
  865.         Abort();
  866.         /* NOTREACHED */
  867.     }
  868. }
  869.  
  870.  
  871. /*
  872.  * Compute the offset of the focus from the beginning of the current node.
  873.  * This may be input again to fixfocus to allow restoration of this position.
  874.  */
  875.  
  876. Visible int
  877. focoffset(ep)
  878.     register environ *ep;
  879. {
  880.     node nn;
  881.     register node n;
  882.     register string *rp;
  883.     register int w;
  884.     register int len;
  885.     register int i;
  886.  
  887.     switch (ep->mode) {
  888.  
  889.     case WHOLE:
  890.     case SUBLIST:
  891.         return 0;
  892.  
  893.     case ATBEGIN:
  894.         return ep->spflag;
  895.  
  896.     case ATEND:
  897.         w = width(tree(ep->focus));
  898.         if (w < 0)
  899.             return w;
  900.         return w + ep->spflag;
  901.  
  902.     case SUBSET:
  903.     case FHOLE:
  904.     case VHOLE:
  905.     case SUBRANGE:
  906.         n = tree(ep->focus);
  907.         rp = noderepr(n);
  908.         len = 0;
  909.         for (i = 1; i < ep->s1; ++i) {
  910.             if (i&1)
  911.                 w = Fwidth(rp[i/2]);
  912.             else {
  913.                 nn = child(n, i/2);
  914.                 w = width(nn);
  915.             }
  916.             if (w < 0) {
  917.                 if (len >= 0)
  918.                     len = w;
  919.                 else
  920.                     len += w;
  921.             }
  922.             else if (len >= 0)
  923.                 len += w;
  924.         }
  925.         if (ep->mode == SUBSET || len < 0)
  926.             return len;
  927.         return len + ep->s2 + ep->spflag;
  928.  
  929.     default:
  930.         Abort();
  931.         /* NOTREACHED */
  932.     }
  933. }
  934.  
  935.  
  936. /*
  937.  * Return the first character of the focus (maybe '\n'; 0 if zero-width).
  938.  */
  939.  
  940. Visible int
  941. focchar(ep)
  942.     environ *ep;
  943. {
  944.     node n = tree(ep->focus);
  945.     string str;
  946.     string *rp;
  947.     int i;
  948.     int c;
  949.  
  950.     switch (ep->mode) {
  951.  
  952.     case VHOLE:
  953.     case FHOLE:
  954.     case ATBEGIN:
  955.     case ATEND:
  956.         return 0;
  957.  
  958.     case WHOLE:
  959.     case SUBLIST:
  960.         return nodechar(n);
  961.  
  962.     case SUBSET:
  963.         rp = noderepr(n);
  964.         for (i = ep->s1; i <= ep->s2; ++i) {
  965.             if (i&1) {
  966.                 if (!Fw_zero(rp[i/2]))
  967.                 return rp[i/2][0];
  968.             }
  969.             else {
  970.                 c = nodechar(child(n, i/2));
  971.                 if (c)
  972.                     return c;
  973.             }
  974.         }
  975.         return 0;
  976.  
  977.     case SUBRANGE:
  978.         if (ep->s1&1)
  979.             str = noderepr(n)[ep->s1/2];
  980.         else {
  981.             Assert(Type(child(n, ep->s1/2)) == Tex);
  982.             str = Str((value)child(n, ep->s1/2));
  983.         }
  984.         return str[ep->s2];
  985.  
  986.     default:
  987.         Abort();
  988.         /* NOTREACHED */
  989.  
  990.     }
  991. }
  992.  
  993.  
  994. /*
  995.  * Subroutine to return first character of node.
  996.  */
  997.  
  998. Visible int
  999. nodechar(n)
  1000.     node n;
  1001. {
  1002.     string *rp;
  1003.     int nch;
  1004.     int i;
  1005.     int c;
  1006.  
  1007.     if (Type(n) == Tex)
  1008.         return Str((value)n)[0];
  1009.     rp = noderepr(n);
  1010.     if (!Fw_zero(rp[0]))
  1011.         return rp[0][0];
  1012.     nch = nchildren(n);
  1013.     for (i = 1; i <= nch; ++i) {
  1014.         c = nodechar(child(n, i));
  1015.         if (c)
  1016.             return c;
  1017.         if (!Fw_zero(rp[i]))
  1018.             return rp[i][0];
  1019.     }
  1020.     return 0;
  1021. }
  1022.  
  1023.  
  1024. /*
  1025.  * Function to compute the actual indentation level at the focus.
  1026.  */
  1027.  
  1028. Visible int
  1029. focindent(ep)
  1030.     environ *ep;
  1031. {
  1032.     int y = Ycoord(ep->focus);
  1033.     int x = Xcoord(ep->focus);
  1034.     int level = Level(ep->focus);
  1035.     node n = tree(ep->focus);
  1036.  
  1037.     switch (ep->mode) {
  1038.  
  1039.     case WHOLE:
  1040.     case ATBEGIN:
  1041.     case SUBLIST:
  1042.         break;
  1043.  
  1044.     case ATEND:
  1045.         evalcoord(n, 1 + nchildren(n), &y, &x, &level);
  1046.         break;
  1047.  
  1048.     case SUBSET:
  1049.     case FHOLE:
  1050.     case VHOLE:
  1051.         evalcoord(n, ep->s1/2, &y, &x, &level);
  1052.         break;
  1053.  
  1054.     default:
  1055.         Abort();
  1056.     }
  1057.     return level;
  1058. }
  1059.  
  1060.  
  1061. /*
  1062.  * Routines to move 'environ' structures.
  1063.  */
  1064.  
  1065. emove(s, d)
  1066.     environ *s;
  1067.     environ *d;
  1068. {
  1069. #ifdef STRUCTASS
  1070.     *d = *s;
  1071. #else !STRUCTASS
  1072.     d->focus = s->focus;
  1073.  
  1074.     d->mode = s->mode;
  1075.     d->copyflag = s->copyflag;
  1076.     d->spflag = s->spflag;
  1077.     d->changed = s->changed;
  1078.  
  1079.     d->s1 = s->s1;
  1080.     d->s2 = s->s2;
  1081.     d->s3 = s->s3;
  1082.  
  1083.     d->highest = s->highest;
  1084.  
  1085.     d->copybuffer = s->copybuffer;
  1086. #ifdef RECORDING
  1087.     d->oldmacro = s->oldmacro;
  1088.     d->newmacro = s->newmacro;
  1089. #endif RECORDING
  1090.  
  1091.     d->generation = s->generation;
  1092. #endif !STRUCTASS
  1093. }
  1094.  
  1095. ecopy(s, d)
  1096.     environ *s;
  1097.     environ *d;
  1098. {
  1099.     emove(s, d);
  1100.     pathcopy(d->focus);
  1101.     copy(d->copybuffer);
  1102. #ifdef RECORDING
  1103.     copy(d->oldmacro);
  1104.     copy(d->newmacro);
  1105. #endif RECORDING
  1106. }
  1107.  
  1108. erelease(e)
  1109.     environ *e;
  1110. {
  1111.     pathrelease(e->focus);
  1112.     release(e->copybuffer);
  1113. #ifdef RECORDING
  1114.     release(e->oldmacro);
  1115.     release(e->newmacro);
  1116. #endif RECORDING
  1117. }
  1118.